//
//  OperationQueueTableViewController.m
//  OperationQueueDemo
//
//  Created by 苏沫离 on 2018/8/10.
//  Copyright © 2018年 苏沫离. All rights reserved.
//
#define CellIdentifer @"UITableViewCell"

#import "OperationQueueTableViewController.h"
#import "OperationAsync.h"
#import "OperationSync.h"

@interface OperationQueueTableViewController ()
@property (nonatomic ,strong) NSArray<NSString *> *titleArray;
@end

@implementation OperationQueueTableViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    
    [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:CellIdentifer];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark - Table view data source

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.titleArray.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifer forIndexPath:indexPath];
    cell.textLabel.text = self.titleArray[indexPath.row];
    cell.textLabel.numberOfLines = 0;
    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
    NSLog(@"开始处理 -------- %@",NSThread.currentThread);
    if (indexPath.row == 0)
    {
        [self customSyncOperationTaskAMethod];
    }
    else if (indexPath.row == 1)
    {
        [self customAsyncOperationTaskAMethod];
    }
    else if (indexPath.row == 2)
    {
        [self operationChildClassMethod];
    }
    else if (indexPath.row == 3)
    {
        [self addSyncDependencyMethod];
    }
    else if (indexPath.row == 4)
    {
        [self addAsyncDependencyMethod];
    }
    else if (indexPath.row == 5)
    {
        [self waitUntilFinishedMethod];
    }
    else if (indexPath.row == 6)
    {
        [self addOperationMethod1];
    }
    else if (indexPath.row == 7)
    {
        [self addOperationMethod];
    }
    else if (indexPath.row == 8)
    {
        [self addOperationMethod2];
    }
    else if (indexPath.row == 9)
    {
        [self addOperationMethod3];
    }
    else if (indexPath.row == 10)
    {
        [self cancelAllOperationsMethod];
    }
    else if (indexPath.row == 11)
    {
        [self currentOperationCountMethod];
    }
    else if (indexPath.row == 12)
    {
        [self maxOperationCountMethod];
    }
    else if (indexPath.row == 13)
    {
        [self suspendOperationMethod];
    }


    NSLog(@"结束处理 -------- %@",NSThread.currentThread);
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
    id task = (__bridge id)(context);
    NSLog(@"%@ ----- %@ === %@",task,keyPath,change);
}

#pragma mark - 自定义NSOperation

- (void)customSyncOperationTaskAMethod
{
    OperationSync *taskA = [[OperationSync alloc] init];
    taskA.completionBlock = ^{
        NSLog(@"结束执行：taskA ------- %@",NSThread.currentThread);
    };

    OperationSync *taskB = [[OperationSync alloc] init];
    taskB.completionBlock = ^{
        NSLog(@"结束执行：taskA ------- %@",NSThread.currentThread);
    };

    
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    NSLog(@"开始执行：taskA ======= %@",NSThread.currentThread);
    [queue addOperation:taskA];
    NSLog(@"开始执行：taskB ======= %@",NSThread.currentThread);
    [queue addOperation:taskB];
    
//    [taskA addObserver:self forKeyPath:@"cancelled" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:(__bridge void * _Nullable)(taskA)];
//    [taskA addObserver:self forKeyPath:@"executing" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:(__bridge void * _Nullable)(taskA)];
//    [taskA addObserver:self forKeyPath:@"finished" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:(__bridge void * _Nullable)(taskA)];
//    [taskA addObserver:self forKeyPath:@"ready" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:(__bridge void * _Nullable)(taskA)];
}


- (void)customAsyncOperationTaskAMethod
{
    OperationAsync *taskA = [[OperationAsync alloc] init];
    taskA.completionBlock = ^{
        NSLog(@"结束执行：taskA ------- %@",NSThread.currentThread);
    };
    
    OperationAsync *taskB = [[OperationAsync alloc] init];
    taskB.completionBlock = ^{
        NSLog(@"结束执行：taskA ------- %@",NSThread.currentThread);
    };
    
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    NSLog(@"开始执行：taskA ======= %@",NSThread.currentThread);
    [queue addOperation:taskA];
    NSLog(@"开始执行：taskB ======= %@",NSThread.currentThread);
    [queue addOperation:taskB];
//
//    [taskA addObserver:self forKeyPath:@"cancelled" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:(__bridge void * _Nullable)(taskA)];
//    [taskA addObserver:self forKeyPath:@"executing" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:(__bridge void * _Nullable)(taskA)];
//    [taskA addObserver:self forKeyPath:@"finished" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:(__bridge void * _Nullable)(taskA)];
//    [taskA addObserver:self forKeyPath:@"ready" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:(__bridge void * _Nullable)(taskA)];
}

#pragma mark - NSOperation子类

- (void)operationChildClassMethod
{
    NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invocationOperationHandleTask:) object:@{}];
    invocationOperation.completionBlock = ^{
        NSLog(@"监听回调：taskA ------- %@",NSThread.currentThread);
    };
    invocationOperation.qualityOfService = NSOperationQueuePriorityLow;

    
    NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"taskB：currentQueue ======= %@",NSOperationQueue.currentQueue);
        NSLog(@"开始执行：taskB ======= %@",NSThread.currentThread);
        [NSThread sleepForTimeInterval:3];//模拟耗时任务
        NSLog(@"结束执行：taskB ------- %@",NSThread.currentThread);
    }];
    blockOperation.completionBlock = ^{
        NSLog(@"监听回调：taskB ------- %@",NSThread.currentThread);
    };
    blockOperation.qualityOfService = NSOperationQueuePriorityHigh;
    NSLog(@"currentQueue ======= %@",NSOperationQueue.currentQueue);
    NSLog(@"mainQueue ======= %@",NSOperationQueue.mainQueue);
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue addOperation:invocationOperation];
    [queue addOperation:blockOperation];

}

- (void)invocationOperationHandleTask:(id)object
{
    NSLog(@"taskA：currentQueue ======= %@",NSOperationQueue.currentQueue);
    NSLog(@"开始执行：taskA ======= %@",NSThread.currentThread);
    [NSThread sleepForTimeInterval:3];//模拟耗时任务
    NSLog(@"结束执行：taskA ------- %@",NSThread.currentThread);
}

#pragma mark - 依赖

- (void)addSyncDependencyMethod
{
    OperationSync *taskA = [[OperationSync alloc] init];
    taskA.completionBlock = ^{
        NSLog(@"结束执行：taskA ------- %@",NSThread.currentThread);
    };
    
    OperationAsync *taskB = [[OperationAsync alloc] init];
    taskB.completionBlock = ^{
        NSLog(@"结束执行：taskB ------- %@",NSThread.currentThread);
    };
    
    [taskB addDependency:taskA];
    
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    NSLog(@"开始执行：taskB ======= %@",NSThread.currentThread);
    [queue addOperation:taskB];
    NSLog(@"开始执行：taskA ======= %@",NSThread.currentThread);
    [queue addOperation:taskA];
}

- (void)addAsyncDependencyMethod
{
    OperationAsync *taskA = [[OperationAsync alloc] init];
    taskA.completionBlock = ^{
        NSLog(@"结束执行：taskA ------- %@",NSThread.currentThread);
    };
    
    OperationAsync *taskB = [[OperationAsync alloc] init];
    taskB.completionBlock = ^{
        NSLog(@"结束执行：taskB ------- %@",NSThread.currentThread);
    };
    
    [taskB addDependency:taskA];
    
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    NSLog(@"开始执行：taskB ======= %@",NSThread.currentThread);
    [queue addOperation:taskB];
    NSLog(@"开始执行：taskA ======= %@",NSThread.currentThread);
    [queue addOperation:taskA];
}

#pragma mark - waitUntilFinished

/*
我们使用``NSBlockOperation```创建了操作A，操作B，操作C，操作D；使用```NSOperationQueue```的实例方法```- addOperation:```将操作A、操作C、操作D添加到操作队列，使用```- addOperations: waitUntilFinished:```方法将操作B添加至操作队列；在添加操作C与操作D之间使用```- waitUntilAllOperationsAreFinished```堵塞当前线程。

 */
- (void)waitUntilFinishedMethod
{
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];

    NSBlockOperation *blockOperationA = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"开始执行：taskA ======= %@",NSThread.currentThread);
        [NSThread sleepForTimeInterval:5];//模拟耗时任务
        NSLog(@"结束执行：taskA ------- %@",NSThread.currentThread);
    }];
    blockOperationA.name = @"com.demo.taskA";
    
    NSBlockOperation *blockOperationB = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"开始执行：taskB ======= %@",NSThread.currentThread);
        [NSThread sleepForTimeInterval:3];//模拟耗时任务
        NSLog(@"结束执行：taskB ------- %@",NSThread.currentThread);
    }];
    blockOperationB.name = @"com.demo.taskB";

    NSBlockOperation *blockOperationC = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"开始执行：taskC ======= %@",NSThread.currentThread);
        [NSThread sleepForTimeInterval:3];//模拟耗时任务
        NSLog(@"结束执行：taskC ------- %@",NSThread.currentThread);
    }];
    blockOperationC.name = @"com.demo.taskC";
    
    NSBlockOperation *blockOperationD = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"开始执行：taskD ======= %@",NSThread.currentThread);
        [NSThread sleepForTimeInterval:3];//模拟耗时任务
        NSLog(@"结束执行：taskD ------- %@",NSThread.currentThread);
    }];
    blockOperationD.name = @"com.demo.taskD";
    
    
    [queue addOperation:blockOperationA];
    [queue addOperations:@[blockOperationB] waitUntilFinished:YES];
    NSLog(@"queue.operations === 1 === %@",queue.operations);
    [queue addOperation:blockOperationC];
    NSLog(@"queue.operations === 2 === %@",queue.operations);
    [queue waitUntilAllOperationsAreFinished];
    [queue addOperation:blockOperationD];
    NSLog(@"queue.operations === 3 === %@",queue.operations);
}

/*
 
我们运行程序，分析打印数据：
 
```
10:21:58 开始处理 -------- <NSThread: 0x60400006f6c0>{number = 1, name = main}
10:21:58 开始执行：taskA ======= <NSThread: 0x60000046bac0>{number = 3, name = (null)}
10:21:58 开始执行：taskB ======= <NSThread: 0x60400046bd80>{number = 4, name = (null)}
10:22:01 结束执行：taskB ------- <NSThread: 0x60400046bd80>{number = 4, name = (null)}
10:22:01 queue.operations === 1 === (
 "<NSBlockOperation: 0x60000044f900>{name = 'com.demo.taskA'}"
 )
10:22:01 queue.operations === 2 === (
 "<NSBlockOperation: 0x60000044f900>{name = 'com.demo.taskA'}",
 "<NSBlockOperation: 0x6000002586c0>{name = 'com.demo.taskC'}"
 )
10:22:01 开始执行：taskC ======= <NSThread: 0x60400046bd80>{number = 4, name = (null)}
10:22:03 结束执行：taskA ------- <NSThread: 0x60000046bac0>{number = 3, name = (null)}
10:22:04 结束执行：taskC ------- <NSThread: 0x60400046bd80>{number = 4, name = (null)}
10:22:04 queue.operations === 3 === (
 "<NSBlockOperation: 0x6000004436c0>{name = 'com.demo.taskD'}"
 )
10:22:04 开始执行：taskD ======= <NSThread: 0x60000046bac0>{number = 3, name = (null)}
10:22:04 结束处理 -------- <NSThread: 0x60400006f6c0>{number = 1, name = main}
10:22:07 结束执行：taskD ------- <NSThread: 0x60000046bac0>{number = 3, name = (null)}
```
 
通过打印数据：
* ```taskB```执行完毕之后，才开始执行```taskC```：这是因为```- addOperations: waitUntilFinished:```方法的第二个参数```wait```如果```YES```，则阻塞当前线程，直到所有指定的操作执行完毕；如果为```NO```，则不会堵塞当前线程，立即返回。
* ```taskC```执行完毕之后，才调用```结束处理```这句代码：这是因为```- waitUntilAllOperationsAreFinished```方法会阻塞当前线程，直到队列中所有操作执行完成为止；在此期间，当前线程不能向队列添加操作，但其他线程可以。
* 通过```queue.operations === 1 ===```可以看到此时的操作队列只有操作```com.demo.taskA```：这是因为```- addOperations: waitUntilFinished:```方法的第二个参数```wait```如果```YES```，则阻塞当前线程，直到指定的操作执行完毕，这时会将指定的操作移除操作队列；
* 通过```queue.operations === 2 ===``` 与 ```queue.operations === 3 ===``` 的结果对比，可以看到```- waitUntilAllOperationsAreFinished```之前的操作都被移除操作队列
 */

#pragma mark - addOperation

/*
 我们使用``NSBlockOperation```创建了一个耗时操作；创建了两个操作队列使用```NSOperationQueue```的实例方法```- addOperation:```将操作添加到这两个操作操作队列，
 */

- (void)addOperationMethod
{
    NSOperationQueue *queue1 = [[NSOperationQueue alloc] init];
    NSOperationQueue *queue2 = [[NSOperationQueue alloc] init];
    
    NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"开始执行 ======= %@",NSThread.currentThread);
        [NSThread sleepForTimeInterval:5];//模拟耗时任务
        NSLog(@"结束执行 ------- %@",NSThread.currentThread);
    }];

    [queue1 addOperation:blockOperation];
    [queue2 addOperation:blockOperation];
}

/*
运行这段代码，发现程序异常终止：操作已经加入到队列中

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSOperationQueue addOperation:]: operation is already enqueued on a queue'
 
 */


- (void)addOperationMethod1
{
    NSOperationQueue *queue1 = [[NSOperationQueue alloc] init];
    queue1.name = @"com.demo.operationQueue1";
    NSOperationQueue *queue2 = [[NSOperationQueue alloc] init];
    queue2.name = @"com.demo.operationQueue2";

    NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"开始执行 ======= %@",NSThread.currentThread);
        [NSThread sleepForTimeInterval:5];//模拟耗时任务
        NSLog(@"结束执行 ------- %@",NSThread.currentThread);
    }];
    
    [queue1 addOperation:blockOperation];
    [queue1 waitUntilAllOperationsAreFinished];
    NSLog(@"queue.operations ====== %@",queue1.operations);
    [queue2 addOperation:blockOperation];
}
/*
 运行这段代码，发现程序异常终止：操作已经完成，无法加入队列
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSOperationQueue addOperation:]: operation is finished and cannot be enqueued'
 */



- (void)addOperationMethod2
{
    NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"开始执行 ======= %@",NSThread.currentThread);
        [NSThread sleepForTimeInterval:3];//模拟耗时任务
        NSLog(@"结束执行 ------- %@",NSThread.currentThread);
    }];
    [blockOperation start];
    
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    queue.name = @"com.demo.blockQueue";
    [queue addOperation:blockOperation];
}

/*
 
 运行这段代码，发现程序异常终止：操作已经完成，无法加入队列
 
 Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSOperationQueue addOperation:]: operation is finished and cannot be enqueued'

 */

- (void)addOperationMethod3
{
    OperationAsync *task = [[OperationAsync alloc] init];
    [task start];
    
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    queue.name = @"com.demo.asyncQueue";
    [queue addOperation:task];
}



/*
 运行这段代码，发现程序异常终止：正在执行操作，无法加入队列
 Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSOperationQueue addOperation:]: operation is executing and cannot be enqueued'
 
 */

#pragma mark - cancelOperations

/*
```- (void)cancelAllOperations```|取消所有排队和执行的操作。此方法会对当前操作队列中的所有操作调用```-(void)cancel```方法。取消操作不会自动将它们从队列中删除或停止当前正在执行的操作。对于排队和等待执行的操作，队列必须仍然尝试执行操作，然后才会识别它被取消并将其移动到完成状态。对于已经执行的操作，操作对象本身必须检查是否取消，并停止正在执行的操作，以便能够移动到完成状态。在这两种情况下，已完成(或已取消)的操作在从队列中删除之前仍然有机会执行其完成块。

 */
- (void)cancelAllOperationsMethod
{
}

#pragma mark - 并发数

- (void)currentOperationCountMethod
{
    NSBlockOperation *blockOperationA = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"开始执行 taskA ==== operationCount : %lu === %@",NSOperationQueue.currentQueue.operationCount,NSThread.currentThread);
        
        [NSThread sleepForTimeInterval:1];//模拟耗时任务
        NSLog(@"结束执行 taskA ==== operationCount : %lu === %@",NSOperationQueue.currentQueue.operationCount,NSThread.currentThread);
    }];
    
    NSBlockOperation *blockOperationB = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"开始执行 taskB ==== operationCount : %lu === %@",NSOperationQueue.currentQueue.operationCount,NSThread.currentThread);
        [NSThread sleepForTimeInterval:3];//模拟耗时任务
        NSLog(@"结束执行 taskB ==== operationCount : %lu === %@",NSOperationQueue.currentQueue.operationCount,NSThread.currentThread);
    }];
    
    NSBlockOperation *blockOperationC = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"开始执行 taskC ==== operationCount : %lu === %@",NSOperationQueue.currentQueue.operationCount,NSThread.currentThread);
        [NSThread sleepForTimeInterval:5];//模拟耗时任务
        NSLog(@"结束执行 taskC ==== operationCount : %u === %@",NSOperationQueue.currentQueue.operationCount,NSThread.currentThread);
    }];
    
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    queue.name = @"com.demo.asyncQueue";
    [queue addOperation:blockOperationA];
    [queue addOperation:blockOperationB];
    [queue addOperation:blockOperationC];

}

- (void)maxOperationCountMethod
{
    NSBlockOperation *blockOperationA = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"开始执行 taskA ==== operationCount : %lu === %@",NSOperationQueue.currentQueue.operationCount,NSThread.currentThread);
        
        [NSThread sleepForTimeInterval:1];//模拟耗时任务
        NSLog(@"结束执行 taskA ==== operationCount : %lu === %@",NSOperationQueue.currentQueue.operationCount,NSThread.currentThread);
    }];
    
    NSBlockOperation *blockOperationB = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"开始执行 taskB ==== operationCount : %lu === %@",NSOperationQueue.currentQueue.operationCount,NSThread.currentThread);
        [NSThread sleepForTimeInterval:3];//模拟耗时任务
        NSLog(@"结束执行 taskB ==== operationCount : %lu === %@",NSOperationQueue.currentQueue.operationCount,NSThread.currentThread);
    }];
    
    NSBlockOperation *blockOperationC = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"开始执行 taskC ==== operationCount : %lu === %@",NSOperationQueue.currentQueue.operationCount,NSThread.currentThread);
        [NSThread sleepForTimeInterval:5];//模拟耗时任务
        NSLog(@"结束执行 taskC ==== operationCount : %u === %@",NSOperationQueue.currentQueue.operationCount,NSThread.currentThread);
    }];
    
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    queue.name = @"com.demo.asyncQueue";
    queue.maxConcurrentOperationCount = 1;
    [queue addOperation:blockOperationA];
    [queue addOperation:blockOperationB];
    [queue addOperation:blockOperationC];
    NSOperationQueueDefaultMaxConcurrentOperationCount;
}


- (void)suspendOperationMethod
{
    NSBlockOperation *blockOperationA = [NSBlockOperation blockOperationWithBlock:^{
        
        NSOperationQueue.currentQueue.suspended = YES;
        NSLog(@"开始执行 taskA ==== operationCount : %lu === %@",(long)NSOperationQueue.currentQueue.operationCount,NSThread.currentThread);
        [NSThread sleepForTimeInterval:1];//模拟耗时任务
        NSLog(@"结束执行 taskA ==== operationCount : %lu === %@",(long)NSOperationQueue.currentQueue.operationCount,NSThread.currentThread);
    }];
    
    NSBlockOperation *blockOperationB = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"开始执行 taskB ==== operationCount : %lu === %@",(long)NSOperationQueue.currentQueue.operationCount,NSThread.currentThread);
        [NSThread sleepForTimeInterval:3];//模拟耗时任务
        NSOperationQueue.currentQueue.suspended = NO;
        NSLog(@"结束执行 taskB ==== operationCount : %lu === %@",(long)NSOperationQueue.currentQueue.operationCount,NSThread.currentThread);
    }];
    
    NSBlockOperation *blockOperationC = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"开始执行 taskC ==== operationCount : %lu === %@",(long)NSOperationQueue.currentQueue.operationCount,NSThread.currentThread);
        [NSThread sleepForTimeInterval:5];//模拟耗时任务
        NSLog(@"结束执行 taskC ==== operationCount : %lu === %@",(long)NSOperationQueue.currentQueue.operationCount,NSThread.currentThread);
    }];
    
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    queue.name = @"com.demo.asyncQueue";
    queue.maxConcurrentOperationCount = 2;
    [queue addOperation:blockOperationA];
    [queue addOperation:blockOperationB];
    [queue addOperation:blockOperationC];
}

#pragma mark - setter and getter

- (NSArray<NSString *> *)titleArray
{
    if (_titleArray == nil)
    {
        _titleArray = @[@"同步NSOperation放入队列",
                        @"异步NSOperation放入队列",
                        @"NSInvocationOperation与NSBlockOperation放入队列",
                        @"同步NSOperation依赖",
                        @"异步NSOperation依赖",
                        @"waitUntil",
                        @"addOperation添加已移除的操作",
                        @"addOperation",
                        @"addOperation1",
                        @"addOperation2",
                        @"cancelAllOperations",
                        @"operationCount",
                        @"maxOperationCount",
                        @"suspended"];
    }
    return _titleArray;
}

@end
